package com.smartstate.EnvironmentMonitor.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.nacos.shaded.org.checkerframework.checker.units.qual.A;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smartstate.EnvironmentMonitor.dto.PageDTO;
import com.smartstate.EnvironmentMonitor.dto.ReportDTO;
import com.smartstate.EnvironmentMonitor.entity.Report;
import com.smartstate.EnvironmentMonitor.mapper.DataMapper;
import com.smartstate.EnvironmentMonitor.mapper.HistoryMapper;
import com.smartstate.EnvironmentMonitor.mapper.ObjMoudelMapper;
import com.smartstate.EnvironmentMonitor.mapper.ReportMapper;
import com.smartstate.EnvironmentMonitor.service.ReportService;
import com.smartstate.EnvironmentMonitor.service.ServiceBase;
import com.smartstate.EnvironmentMonitor.vo.ReportVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

@Service
@Slf4j
public class ReportImpl extends ServiceImpl<ReportMapper, Report> implements ReportService {

    @Resource
    private ReportMapper reportMapper;

    @Resource
    private DataMapper dataMapper;

    @Resource
    private HistoryMapper historyMapper;

    @Resource
    private ObjMoudelMapper objMoudelMapper;

    /**
     * 日报查询默认单位分，月表查询默认单位时
     * @param
     * @return
     */
    @Override
    public List<Report> queryByCondition(PageDTO pageDTO) {
        ReportDTO reportDTO = (ReportDTO) pageDTO.getDto();
        if (reportDTO != null){
            if (reportDTO.getType() != null){
                reportDTO = checkType(reportDTO);
            }else if(reportDTO.getId() != null){
                reportDTO = tranform(reportDTO);
            }
        }
        return reportMapper.getQueryData(checkType(reportDTO));
    }

    @Override
    public List<Map<String, String>> exportExcel(PageDTO pageDTO) {
        ReportDTO reportDTO = (ReportDTO) pageDTO.getDto();
        //////////////////////////////////////////////////////////
//        传输数据集合
        List<Map<String, String>> arrayListMap = new ArrayList<>();
//        获取要查询的设备id集合
        if(reportDTO.getId() == null){
            return null;
        }
        if (reportDTO.getType() != null){
            pageDTO.setDto(checkType(reportDTO));
        }
        pageDTO.setDto(getTimeUnit(reportDTO));
        List<ReportVO> reportVOS = new ArrayList<>();
        List<String> objIdList = new ArrayList<>();
        objIdList.add(reportDTO.getId());
        objIdList = queryByQueryId(reportDTO.getId(), objIdList);
        for (String id : objIdList) {
            if(!dataMapper.check(id).isEmpty()){
                List<ReportVO> reportVOList = dataMapper.queryDeviceIdByObjid(id);
                reportVOS.addAll(reportVOList);
            }
        }
//        遍历所有deivceId对于的表
        DateTime dateTime = new DateTime();
        String nowDate = dateTime.toString();
        for (ReportVO reportVO : reportVOS) {
            String tableIsEmpty = historyMapper.queryTableIsEmpty(reportVO.getId());
            if (tableIsEmpty != null){
                List<Report> repors = reportMapper.exportExcel(reportDTO, reportVO.getId(), nowDate);
//                用来获取arrayListMap下标
                int count = 0;
//                每一个deviceId构造一列
                for (Report repor : repors) {
                    Map<String, String> hashMap = null;
                    if(arrayListMap.size() > count){
                        hashMap = arrayListMap.get(count);
                    }else {
                        hashMap = new HashMap<>();
                    }
                    hashMap.put(reportVO.getDeviceId() + "." + "dewPoint",String.valueOf(repor.getDewPoint()));
                    hashMap.put(reportVO.getDeviceId() + "." + "humidity",String.valueOf(repor.getHumidity()));
                    hashMap.put(reportVO.getDeviceId() + "." + "littleParticle",String.valueOf(repor.getLittleParticle()));
                    hashMap.put(reportVO.getDeviceId() + "." + "longParticle",String.valueOf(repor.getLongParticle()));
                    hashMap.put(reportVO.getDeviceId() + "." + "staticPressure",String.valueOf(repor.getStaticPressure()));
                    hashMap.put(reportVO.getDeviceId() + "." + "temperature",String.valueOf(repor.getTemperature()));
                    hashMap.put("time",String.valueOf(DateUtil.format(repor.getDateTime(), "yyyy-MM-dd HH:mm:ss")));
                    if(arrayListMap.size() > count){
                        arrayListMap.set(count, hashMap);
                    }else {
                        arrayListMap.add(hashMap);
                    }
                    count ++;
                }
            }
        }
        return arrayListMap;
    }

    /**
     * 自定义查询，开始时间与结束时间为一天之内，单位才能设置为秒，超过七天单位为时，一般默认分
     * @return
     */
    @Override
    public List<Report> queryByReportDTO(ReportDTO reportDTO) {
        reportDTO = tranform(reportDTO);
        return reportMapper.getQueryData(reportDTO);
    }


    /**
     * 分页查询 + 日月报查询 + 自定义查询
     * @param pageDTO
     * @return
     */
    @Override
    public Page queryAllPageByPageDTO(PageDTO pageDTO) {
        Page<Map<String, String>> page = new Page<>();
//        传输数据集合
        List<Map<String, String>> arrayListMap = new ArrayList<>();
//        偏移量
        long offset = (pageDTO.getPage() - 1) * pageDTO.getSize();
        ReportDTO dto = (ReportDTO) pageDTO.getDto();
//        获取要查询的设备主键id集合
        if(dto.getId() == null){
            return null;
        }
        if (dto.getType() != null){
            pageDTO.setDto(checkType(dto));
        }

        pageDTO.setDto(getTimeUnit(dto));
        List<String> objIdList = new ArrayList<>();
        objIdList.add(dto.getId());
        objIdList = queryByQueryId(dto.getId(), objIdList);
        List<ReportVO> reportVOS = new ArrayList<>();
        for (String id : objIdList) {
            if(dataMapper.check(id) != null && dataMapper.check(id).size() > 0){
                List<ReportVO> reportVOList = dataMapper.queryDeviceIdByObjid(id);
                reportVOS.addAll(reportVOList);
            }
        }
//        用来标识arrayListMap是否添加了pageDTO.size大小的的map
        long total = 0;
//        遍历所有deivceId对于的表
        ArrayList<Long> totalList = new ArrayList<>();
        DateTime dateTime = new DateTime();
        String nowDate = dateTime.toString();
        for (ReportVO reportVO : reportVOS) {
//            判断超级表中environmentalmonitoring市场存在deviceId对于的表名
            String tableIsEmpty = historyMapper.queryTableIsEmpty(reportVO.getId());
            if (tableIsEmpty != null){
                List<Report> repors = reportMapper.queryAllPageByPageDTO(pageDTO, reportVO.getId(), offset, nowDate);
//                获取每各deviceId记录大小,最后取最大值
                if (reportMapper.queryDateIsEmpty(pageDTO, reportVO.getId(), nowDate) != null){
                    total = reportMapper.queryAllPageDTO(pageDTO, reportVO.getId(), nowDate);
                    totalList.add(total);
                }
//                用来获取arrayListMap下标
                int count = 0;
//                每一个deviceId构造一列
                Map<String, String> hashMap = null;
                for (Report repor : repors) {
//                    数据有几行生成几个hashMap
                    if (arrayListMap.size() > count){
                        hashMap = arrayListMap.get(count);
                    }else {
                        hashMap = new HashMap<>();
                        arrayListMap.add(hashMap);
                    }
                    hashMap.put(reportVO.getDeviceId() + "." + "dewPoint",String.valueOf(repor.getDewPoint()));
                    hashMap.put(reportVO.getDeviceId() + "." + "humidity",String.valueOf(repor.getHumidity()));
                    hashMap.put(reportVO.getDeviceId() + "." + "littleParticle",String.valueOf(repor.getLittleParticle()));
                    hashMap.put(reportVO.getDeviceId() + "." + "longParticle",String.valueOf(repor.getLongParticle()));
                    hashMap.put(reportVO.getDeviceId() + "." + "staticPressure",String.valueOf(repor.getStaticPressure()));
                    hashMap.put(reportVO.getDeviceId() + "." + "temperature",String.valueOf(repor.getTemperature()));
                    hashMap.put("time",String.valueOf(DateUtil.format(repor.getDateTime(), "yyyy-MM-dd HH:mm:ss")));
                    arrayListMap.set(count, hashMap);
                    count ++;
                }
            }
        }
        if(totalList.size() > 0){
            total = Collections.max(totalList);
        }
//        获取分页数
        long pages = (long) Math.ceil((double) total / page.getSize());
////        设置page属性
        page.setRecords(arrayListMap);
        page.setTotal(total);
        page.setPages(pages);
        page.setSize(pageDTO.getSize());
        return page;
    }

    @Override
    public Page<Report> queryAllPageByDTO(PageDTO pageDTO) {
        return null;
    }

    /**
     * 根据属性名称获取，属性对应数据库表字段名
     * @param object
     * @param name
     * @return
     */
    public String getField(Object object, String name){
        Field[] fields = object.getClass().getDeclaredFields();
        TableField tableField = null;
        for (Field field : fields) {
            field.setAccessible(true);
            if(name.equals(field.getName())){
                tableField = field.getAnnotation(TableField.class);
                break;
            }
        }
        return tableField.value();
    }

    /**
     * 日报或月报查询判断，并输入时间数据
     * @param reportDTO
     * @return
     */
    public ReportDTO checkType(ReportDTO reportDTO){
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String today = simpleDateFormat.format(date);
        String preDay = null;
        //判断是日查询还是月查询
        if (reportDTO.getType().equals("day")){
            simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            preDay = simpleDateFormat.format(date);
            preDay += " 00:00:00";
            reportDTO.setTimeUnit("m");
        }else{
            simpleDateFormat = new SimpleDateFormat("yyyy-MM");
            preDay = simpleDateFormat.format(date);
            preDay += "-01 00:00:00";
            reportDTO.setTimeUnit("h");
        }
        reportDTO.setTimeNumber("1");
        reportDTO.setStartTime(preDay);
        reportDTO.setEndTime(today);
        return reportDTO;
    }


    /**
     * 数据转换，如果传入时间格式为yyyy/MM/dd *转换为yyyy-MM-dd
     * @param reportDTO
     * @return
     */
    public ReportDTO tranform(ReportDTO reportDTO){
        String date = reportDTO.getStartTime();
        date = date.replace("/", "-");
        reportDTO.setStartTime(date);
        date = reportDTO.getEndTime();
        date = date.replace("/", "-");
        reportDTO.setEndTime(date);
        return reportDTO;
    }


    /**
     * 递归该id对应的子节点
     * @param id
     * @return
     */
    public List<String> queryByQueryId(String id, List<String> idList){
        List<String> ids = objMoudelMapper.queryId(id);
        if (ids == null || ids.size() == 0) {
            return idList;
        }
        idList.addAll(ids);
        for (String s : ids) {
            idList = queryByQueryId(s, idList);
        }
        return idList;
    }

    /**
     * 时间换算
     * @param reportDTO
     * @return
     */
    public ReportDTO getTimeUnit(ReportDTO reportDTO){
        String timeNumber = reportDTO.getTimeNumber();
        switch (timeNumber){
            case "1" :
                reportDTO.setTimeUnit("s");
                break;
            case "60":
                reportDTO.setTimeUnit("m");
                break;
            case "3600":
                reportDTO.setTimeUnit("h");
                break;
            default:
                reportDTO.setTimeUnit("d");
        }
        reportDTO.setTimeNumber("1");
        return reportDTO;
    }
}
